package com.settlement.system.controller;

import com.alibaba.excel.context.AnalysisContext;
import com.settlement.system.common.enums.ReturnStatusEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.common.*;
import com.settlement.system.csv.CsvDatas;
import com.settlement.system.csv.CsvExportBuilder;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.entity.SysUser;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.*;
import com.settlement.system.service.csv.WpAuditCsvDatas;
import com.settlement.system.service.extend.BatchSave;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * wp-稽核明细 前端控制器
 *
 * @author xiaochuan
 * @since 2020-11-25
 */

@Api(tags = "wp-稽核明细", description = "wp-稽核明细")
@RestController
@RequestMapping("/wp/audit/dtl")
@Slf4j
public class TblWpAuditStaticDtlController extends ExcelController<TblWpAuditStaticDtl> {

    public static final String WP_AUDIT_STATIC = "acs_wp_audit_batch_number";

    private ExecutorService executors = Executors.newFixedThreadPool(1);

    @Resource
    private ITblWpAuditStaticDtlService tblWpAuditStaticDtlService;

    @Resource
    private ITblWpVendorConfigService tblWpVendorConfigService;

    @Resource
    private ITblWpBrandUnitConfigService tblWpBrandUnitConfigService;

    @Resource
    private ITblWpAuditCloseAccountService tblWpAuditCloseAccountService;

    @Resource
    private ITblWpAuditArchiveRecordService tblWpAuditArchiveRecordService;

    @Resource
    private ITblWpAuditArchiveResultService tblWpAuditArchiveResultService;

    @Override
    public IBaseService init() {
        return tblWpAuditStaticDtlService;
    }

    private static final Date DEFAULT_EFFECTIVE_DATE = DateUtil.parseToDate("2000-01-01", "yyyy-MM-dd");

    @Override
    public Class<?> getModelClass() {
        return TblWpAuditStaticDtl.class;
    }

    @Override
    @PostMapping("import")
    @CacheEvict(cacheNames = {"wpStoreConfigByStoreName", "wpVendorByCode", "wpBrandByBrandUnit", "wpAccountByShopNo"},
            allEntries = true, beforeInvocation = true)
    public ObjectDataResponse importFile(MultipartFile file, HttpServletRequest request) {
        return super.importFile(file, request);
    }

    @Override
    @ApiOperation("分页查询")
    @RequestMapping(value = "list", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse getPageList(HttpServletRequest request, @RequestBody BasePager<Map<String, Object>> model) throws ServiceException {
        Map<String, Object> result = new HashMap<>(16);
        try {
            setParamsModel(model.getModel());

            String verifition = verifyRequest(model.getModel());
            if (!StringUtils.isEmpty(verifition)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), verifition);
            }
            TblWpAuditStaticDtl foot = null;
            List<TblWpAuditStaticDtl> rows = tblWpAuditStaticDtlService.selectByPage(new SinglePage(model), model.getModel(),
                    model.getOrderByField(), model.getOrderBy());
            if (!CollectionUtils.isEmpty(rows)) {
                foot = tblWpAuditStaticDtlService.getFoot(model.getModel());
            }
            result.put("rows", rows);
            if (null != foot) {
                result.put("total", foot.getCountSum());
                result.put("foot", foot);
            } else {
                result.put("total", 0);
                result.put("foot", new TblWpAuditStaticDtl());
            }
            return new ObjectDataResponse<Map>(result, 200, "获取列表成功");
        } catch (Exception ex) {
            log.error("获取列表出错", ex);
            throw new ServiceException("获取列表失败，请联系管理员！", ex);
        }
    }

    @ApiOperation("分页查询")
    @RequestMapping(value = "archive", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse archive(HttpServletRequest request, @RequestBody Map<String, Object> model) throws ServiceException {
        Map<String, Object> result = new HashMap<>(16);
        TblWpAuditArchiveRecord record = null;
        try {
            Map<String, Object> params = new HashMap<>(model);
            SysUserDetails user = SecurityUtils.getUser();;
            setParamsModel(model);

            String verifition = verifyRequest(model);
            if (!StringUtils.isEmpty(verifition)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), verifition);
            }

            boolean ifCanRun = RedisUtil.checkBeforeStart(TblWpAuditArchiveRecord.class.getName());
            if (!ifCanRun) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), "已有存档操作进行中，请稍后再试");
            }

            int unCompletedCount = tblWpAuditArchiveRecordService.selectCountUnCompleted();
            if (unCompletedCount > 0) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), "有未完成的存档操作进行中，请稍后再试");
            }

            record = saveArchiveRecordBeforeQuery(params);

            TblWpAuditStaticDtl foot = tblWpAuditStaticDtlService.getFoot(model);

            if (null != foot) {
                record.setUnBalancePoSkuQty(Integer.parseInt(foot.getPoBarCode()));
                record.setUnBalanceAmount(foot.getUnBalanceAmount());
                record.setUnBalanceQty(foot.getUnBalanceQty());
            } else {
                record.setUnBalancePoSkuQty(0);
                record.setUnBalanceAmount(BigDecimal.ZERO);
                record.setUnBalanceQty(0);
            }

            String shopNos = record.getShopNos();
            Future<?> f = executors.submit(() -> {
                try {
                    tblWpAuditStaticDtlService.saveArchiveResult(model, shopNos);
                } catch (ServiceException e) {
                    log.error(e.getMessage(), e);
                    throw new RuntimeException(e);
                }
            });

            f.get();

            record.setUpdateTime(new Date());
            record.setUpdateUser(user.getUsername());
            tblWpAuditArchiveRecordService.update(record);

            return new ObjectDataResponse<Map>(result, 200, "获取列表成功");
        } catch (Exception ex) {
            log.error("获取列表出错", ex);
            if (record != null) {
                tblWpAuditArchiveRecordService.deleteById(record);
            }
            throw new ServiceException("获取列表失败，请联系管理员！", ex);
        } finally {
            RedisUtil.clearTaskIfPossible(TblWpAuditArchiveRecord.class.getName());
        }
    }


    String sortShopNos(String shopNos) {
        String recordShopNos = shopNos//.replaceAll(",","/")
                .replaceAll("\\(", "")
                .replaceAll("\\)", "")
                .replaceAll("\\'", "");

        List<String> shopNoList = Arrays.asList(recordShopNos.split(","));
        shopNoList.sort(null);
        recordShopNos = shopNoList.toString().replaceAll("[\\[\\]\\s]", "");
        recordShopNos = recordShopNos.replaceAll(",", "/");
        return recordShopNos;
    }

    TblWpAuditArchiveRecord saveArchiveRecordBeforeQuery(Map<String, Object> params) throws ServiceException {
        SysUserDetails user = SecurityUtils.getUser();;
        String sendDate = params.get("sendDate") != null ? params.get("sendDate").toString() : "";
        String billDate = params.get("billDate") != null ? params.get("billDate").toString() : "";
        String rssDate = params.get("rssDate") != null ? params.get("rssDate").toString() : "";
        String sendInitDate = params.get("sendInitDate") != null ? params.get("sendInitDate").toString() : "\t";
        String billInitDate = params.get("billInitDate") != null ? params.get("billInitDate").toString() : "\t";
        String rssInitDate = params.get("rssInitDate") != null ? params.get("rssInitDate").toString() : "\t";
        String shopNos = params.get("shopNos") != null ? params.get("shopNos").toString() : "";

        TblWpAuditArchiveRecord record = new TblWpAuditArchiveRecord();
        record.setSendReturnDate((sendInitDate + "=" + sendDate).replace("-", "").replace("=", "-"));
        record.setBillDate((billInitDate + "=" + billDate).replace("-", "").replace("=", "-"));
        record.setReceiveSendStoreDate((rssInitDate + "=" + rssDate).replace("-", "").replace("=", "-"));
        String recordShopNos = sortShopNos(shopNos);
        record.setShopNos(recordShopNos);
        List<String> vendorCodeList = tblWpVendorConfigService.getVendorCodes(Arrays.asList(recordShopNos.split("\\/")));
        if (!CollectionUtils.isEmpty(vendorCodeList)) {
            String vendorCodes = vendorCodeList.toString().replaceAll("[\\[\\]\\s]", "");
            vendorCodes = vendorCodes.replaceAll(",", "/");
            record.setVendorCode(vendorCodes);
        }
        record.setId(UUID.randomUUID().toString().replace("-", ""));
        record.setCreateUser(user.getUsername());
        record.setCreateTime(new Date());
        tblWpAuditArchiveRecordService.insert(record);
        return record;
    }

    private String verifyRequest(Map<String, Object> params) {
        String sendDate = params.get("sendDate") != null ? params.get("sendDate").toString() : "";
        String billDate = params.get("billDate") != null ? params.get("billDate").toString() : "";
        String rssDate = params.get("rssDate") != null ? params.get("rssDate").toString() : "";
        String sendInitDate = params.get("sendInitDate") != null ? params.get("sendInitDate").toString() : "";
        String billInitDate = params.get("billInitDate") != null ? params.get("billInitDate").toString() : "";
        String rssInitDate = params.get("rssInitDate") != null ? params.get("rssInitDate").toString() : "";
        String shopNos = params.get("shopNos") != null ? params.get("shopNos").toString() : "";


        if (!StringUtils.isEmpty(sendInitDate)
                && sendDate.compareTo(sendInitDate) < 0) {
            return "发退货截至日期不能小于起始日期";
        }

        if (!StringUtils.isEmpty(billInitDate)
                && billDate.compareTo(billInitDate) < 0) {
            return "账单截至日期不能小于起始日期";
        }

        if (!StringUtils.isEmpty(rssInitDate)
                && rssDate.compareTo(rssInitDate) < 0) {
            return "收发存截至日期不能小于起始日期";
        }

        try {
            Date zeroDate = DateUtil.getDate("2000-01-01", "yyyy-MM-dd");

            Date maxInitialDate = tblWpAuditCloseAccountService.getMaxInitialDateByShopNo(shopNos);
            if (StringUtils.isNotBlank(sendInitDate)) {
                Date sendInitDate1 = DateUtil.getDate(sendInitDate, "yyyy-MM-dd");
                if (zeroDate.compareTo(sendInitDate1) != 0 && sendInitDate1.compareTo(maxInitialDate) <= 0) {
                    return "起始日期必须大于店铺初始日期。";
                }
            }
            if (StringUtils.isNotBlank(billInitDate)) {
                Date billInitDate1 = DateUtil.getDate(billInitDate, "yyyy-MM-dd");
                if (zeroDate.compareTo(billInitDate1) != 0 && billInitDate1.compareTo(maxInitialDate) <= 0) {
                    return "起始日期必须大于店铺初始日期。";
                }
            }
            if (StringUtils.isNotBlank(rssInitDate)) {
                Date rssInitDate1 = DateUtil.getDate(rssInitDate, "yyyy-MM-dd");
                if (zeroDate.compareTo(rssInitDate1) != 0 && rssInitDate1.compareTo(maxInitialDate) <= 0) {
                    return "起始日期必须大于店铺初始日期。";
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnStatusEnum.REQUEST_ABNORMAL.getText();
        }

        return null;
    }

    @Override
    public String verifyImportObject(TblWpAuditStaticDtl tblWpAuditStaticDtl, AnalysisContext analysisContext) {

        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getStoreName())) {
            return "唯品仓库名称不能为空";
        }

        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getSupplierNo())) {
            return "供应商编码不能为空";
        }


        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getPoNo())) {
            return "PO单号不能为空";
        }

        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getBarCode())) {
            return "商品条码不能为空";
        }

        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getShopNo())) {
            return "零售店铺编码不能为空";
        }

        if (StringUtils.isEmpty(tblWpAuditStaticDtl.getBrandUnitName())) {
            return "品牌部名称不能为空";
        }

        if (tblWpAuditStaticDtl.getPoType() == null) {
            return "类型只能是不区分，仓JITX，仓JIT，门店JITX中之一";
        }

        try {

            TblWpVendorConfig vendorConfig = tblWpVendorConfigService.getWpVendorByCode(tblWpAuditStaticDtl.getSupplierNo());
            if (vendorConfig == null) {
                return "供应商编码在WP-商户配置不存在";
            }
            TblWpBrandUnitConfig wpBrandUnitConfig = tblWpBrandUnitConfigService.getWpBrandByBrandUnitName(tblWpAuditStaticDtl.getBrandUnitName());

            if (wpBrandUnitConfig == null) {
                return "品牌部编码在WP-品牌对应配置中不存在";
            }
            tblWpAuditStaticDtl.setBrandUnitNo(wpBrandUnitConfig.getBrandUnitNo());

            TblWpAuditCloseAccount wpcloseAccount = tblWpAuditCloseAccountService.getByShopNo(tblWpAuditStaticDtl.getShopNo());

            if (wpcloseAccount == null) {
                return "请先配置wp-稽核锁帐";
            }
            tblWpAuditStaticDtl.setShopName(wpcloseAccount.getShopName());
            tblWpAuditStaticDtl.setEffectiveDate(DEFAULT_EFFECTIVE_DATE);
            tblWpAuditStaticDtl.setExpiredDate(wpcloseAccount.getInitialDate());
        } catch (Exception ex) {
            log.error("验证唯品稽核调账异常", ex);
            return "系统异常";
        }
        return null;
    }

    @Override
    protected void saveData(List<TblWpAuditStaticDtl> datas) throws ServiceException {
        long batchNumber = RedisUtil.incr(WP_AUDIT_STATIC, 1);

        for (TblWpAuditStaticDtl dtl : datas) {
            dtl.setTransactionalNo((int) batchNumber);
        }

        BatchSave batchSave = new BatchSave(tblWpAuditStaticDtlService, datas);

        try {
            batchSave.save();

        } catch (Exception ex) {
            tblWpAuditStaticDtlService.deleteByTransactionalNo(batchNumber);
            log.error("save imported wpAudit exception:", ex);
            throw new ServiceException(batchSave.getErrorMessage(), ex);
        }
    }

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        SysUserDetails user = SecurityUtils.getUser();
        model.put("createUser", user.getUsername());
        model.put("updateUser", user.getUsername());
        FasUtil.formatInQueryCondition(model, "unBalanceQtyType", "unBalanceAmountType", "unSettledBackDiffQtyType",
                "unSettledBackDiffAmountType", "unSettledRefundDiffQtyType",
                "unSettledRefundDiffAmountType", "unSettledOverduefQtyType",
                "unSettledOverdueAmountType", "diffAmountType", "shopNos", "orderSchedule", "poNo", "deliveryType");

        String sendDate = (String) model.get("sendDate");
        String billDate = (String) model.get("billDate");
        String rssDate = (String) model.get("rssDate");

        String sendInitDate = (String) model.get("sendInitDate");
        if (StringUtils.isEmpty(sendInitDate)) {
            model.put("sendInitDate", "2000-01-01");
        }
        String billInitDate = (String) model.get("billInitDate");
        if (StringUtils.isEmpty(billInitDate)) {
            model.put("billInitDate", "2000-01-01");
        }
        String rssInitDate = (String) model.get("rssInitDate");
        if (StringUtils.isEmpty(rssInitDate)) {
            model.put("rssInitDate", "2000-01-01");
        }

        model.put("minSearchDate", StringMathUtils.min(sendDate, billDate, rssDate));
        model.put("maxSearchDate", StringMathUtils.max(sendDate, billDate, rssDate));
        super.setParamsModel(model);
    }

    @Override
    protected CsvDatas getCsvDatas(Map<String, Object> params) {
        return new WpAuditCsvDatas(tblWpAuditCloseAccountService, tblWpAuditStaticDtlService,
                params);
    }

    @Override
    protected Integer getCsvModel(Map<String, Object> params) {
        return CsvExportBuilder.MULTI_ZIP_MODEL;
    }
}
